package com.ryskoo.catering.productmain.repository;

import com.ryskoo.catering.productmain.domain.ProductMainPO;
import com.ryskoo.framework.core.bean.QueryConditionEnum;
import com.ryskoo.framework.core.bean.QueryMessageDTO;
import com.ryskoo.framework.core.repository.BasicJPAImpl;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.hibernate.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Repository
public class ProductMainJPAImpl extends BasicJPAImpl<ProductMainPO> implements IProductMainRepository {
    @Autowired
    ElasticsearchTemplate elasticsearchTemplate;

    @Override
    public void onShelves(List<String> idList) {
        String hql = "update ProductMainPO o set o.state = 1 where o.uuid in (:uuids)";
        Query query = getH4Session().createQuery(hql);
        query.setParameterList("uuids", idList.toArray());
        query.executeUpdate();
    }

    @Override
    public void offShelves(List<String> idList) {
        String hql = "update ProductMainPO o set o.state = 0 where o.uuid in (:uuids)";
        Query query = getH4Session().createQuery(hql);
        query.setParameterList("uuids", idList.toArray());
        query.executeUpdate();
    }

    @Override
    public List<String> getUuidsByCategoryId(String categoryUuid) {
        String hql = "select o.uuid from ProductMainPO o where o.categoryUuid = :categoryUuid";
        Query query = getH4Session().createQuery(hql);
        query.setString("categoryUuid", categoryUuid);
        return query.list();
    }

    @Override
    public void syncToElastic(List<ProductMainPO> list) {
        List<IndexQuery> indexQueryList = new ArrayList<>();
        for (ProductMainPO productMain : list) {
            IndexQuery indexQuery = new IndexQueryBuilder().withObject(productMain).build();
            indexQueryList.add(indexQuery);
        }
        elasticsearchTemplate.bulkIndex(indexQueryList);
        // 强制立即刷新
        elasticsearchTemplate.refresh(ProductMainPO.class);
    }

    @Override
    public List<ProductMainPO> getProductInfoFromES(QueryMessageDTO qm, boolean byPage) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Map<String, Map<String, Object>> queryParams = qm.getQueryParams();
        for (Map.Entry<String, Map<String, Object>> entry : queryParams.entrySet()) {
            String field = entry.getKey();
            Map<String, Object> condition = entry.getValue();
            String operation = MapUtils.getString(condition, "operation");
            Object value = MapUtils.getObject(condition, "value");
            if (null != value && StringUtils.isNotBlank(value.toString())) {
                addOneCondition(boolQueryBuilder, field, value, operation);
            }
        }
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
        // elasticsearchTemplate.queryForList会自带分页
        // 所以当不希望分页的时候，设置一个较大的每页数量，ES默认最大10000
        if (!byPage) {
            qm.setPageShow(10000);
        }
        Pageable pageable = new PageRequest(qm.getQueryPage() - 1, qm.getPageShow());
        searchQueryBuilder.withPageable(pageable);
        searchQueryBuilder.withQuery(boolQueryBuilder);

        return elasticsearchTemplate.queryForList(searchQueryBuilder.build(), ProductMainPO.class);
    }

    @Override
    public int getCountFromES(QueryMessageDTO qm) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Map<String, Map<String, Object>> queryParams = qm.getQueryParams();
        for (Map.Entry<String, Map<String, Object>> entry : queryParams.entrySet()) {
            String field = entry.getKey();
            Map<String, Object> condition = entry.getValue();
            String operation = MapUtils.getString(condition, "operation");
            Object value = MapUtils.getObject(condition, "value");
            if (null != value && StringUtils.isNotBlank(value.toString())) {
                addOneCondition(boolQueryBuilder, field, value, operation);
            }
        }
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
        searchQueryBuilder.withQuery(boolQueryBuilder);
        return (int) elasticsearchTemplate.count(searchQueryBuilder.build(), ProductMainPO.class);
    }

    @Override
    public void deleteProductFromES(List<String> idList) {
        for (String id : idList) {
            elasticsearchTemplate.delete(ProductMainPO.class, id);
        }
    }

    private void addOneCondition(BoolQueryBuilder queryBuilder, String name, Object value, String operation) {
        switch (QueryConditionEnum.valueOf(operation)) {
            case NE:
                queryBuilder.mustNot(QueryBuilders.termQuery(name, value));
                break;
            case EQ:
                queryBuilder.must(QueryBuilders.termQuery(name, value));
                break;
            case LIKE:
                queryBuilder.must(QueryBuilders.matchQuery(name, value));
                break;
            case LLIKE:
                queryBuilder.must(QueryBuilders.wildcardQuery(name, value + "*"));
                break;
            case RLIKE:
                queryBuilder.must(QueryBuilders.wildcardQuery(name, "*" + value));
                break;
            case GT:
                queryBuilder.must(QueryBuilders.rangeQuery(name).gt(value));
                break;
            case GE:
                queryBuilder.must(QueryBuilders.rangeQuery(name).gte(value));
                break;
            case LT:
                queryBuilder.must(QueryBuilders.rangeQuery(name).lt(value));
                break;
            case LE:
                queryBuilder.must(QueryBuilders.rangeQuery(name).lte(value));
                break;
            case IN:
                queryBuilder.must(QueryBuilders.termsQuery(name, value));
                break;
            case NOTIN:
                queryBuilder.mustNot(QueryBuilders.termsQuery(name, value));
                break;
            case BETWEEN:
                Object value1 = ((List) value).get(0);
                Object value2 = ((List) value).get(1);
                queryBuilder.must(QueryBuilders.rangeQuery(name).from(value1).to(value2));
                break;
            case OREQ:
                String[] eqArr = StringUtils.split(name, "#");
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                for (String str : eqArr) {
                    boolQueryBuilder.should(QueryBuilders.termQuery(str, value));
                }
                queryBuilder.must(boolQueryBuilder);
                break;
            case ORLIKE:
                String[] liekArr = StringUtils.split(name, "#");
                BoolQueryBuilder likeBoolQueryBuilder = QueryBuilders.boolQuery();
                for (String str : liekArr) {
                    likeBoolQueryBuilder.should(QueryBuilders.matchQuery(str, value));
                }
                queryBuilder.must(likeBoolQueryBuilder);
                break;
            default:
        }
    }

    @Override
    public void sellOut(List<String> idList) {
        String hql = "update ProductMainPO o set o.isSellOut = true where o.uuid in (:uuids)";
        Query query = getH4Session().createQuery(hql);
        query.setParameterList("uuids", idList.toArray());
        query.executeUpdate();
    }

    @Override
    public void supply(List<String> idList) {
        String hql = "update ProductMainPO o set o.isSellOut = false where o.uuid in (:uuids)";
        Query query = getH4Session().createQuery(hql);
        query.setParameterList("uuids", idList.toArray());
        query.executeUpdate();
    }
}
